package election

import (
	"context"
	"wzgames/pkg/logger"
	"wzgames/pkg/remote/etcd"
)

// ETCD Election

type MasterEventType int

const (
	MasterAdded MasterEventType = iota
	MasterDeleted
	MasterModified
	MasterError
)

type MasterEvent struct {
	Type   MasterEventType
	Master string
	Error  error
}

type LeaderElection interface {
	Campaign() error
	Resign() error
	Close()
	EventsChan() <-chan MasterEvent
}

type Election struct {
	key            string
	value          string
	leaderElection LeaderElection
	stopC          chan struct{}
	callback       func(MasterEvent)
}

func NewElection(key, value string, cb func(MasterEvent)) *Election {
	return &Election{
		key:      key,
		value:    value,
		callback: cb,
		stopC:    make(chan struct{}),
	}
}

func (e *Election) Start(etcdClient *etcd.EtcdClient) error {
	elec, err := NewEtcdLeaderElection(context.Background(), etcdClient.RawClient(), etcdClient.LeaseID(), e.key, e.value)
	if err != nil {
		//logger.Error("err == ", zap.String("error", err.Error()))
		return err
	}
	e.leaderElection = elec

	go e.leaderElection.Campaign()
	go e.onEvent()

	return nil
}

func (e *Election) Stop() {
	e.stopC <- struct{}{}
	e.leaderElection.Close()
}

func (e *Election) onEvent() {
	for {
		select {
		case event := <-e.leaderElection.EventsChan():
			e.callback(event)
		case <-e.stopC:
			logger.Info("[Election] Elect onEvent stopped")
			return
		}
	}
}
